![【全リージョン対応】CloudTrailのログをAthenaのPartition Projectionなテーブルで作る](https://devio2023-media.developers.io/wp-content/uploads/2019/04/amazon-athena.png)
【全リージョン対応】CloudTrailのログをAthenaのPartition Projectionなテーブルで作る
CloudTrailのログを分析するためのAthenaテーブルを作る機会がありましたので、AthenaのPartition Projectionという機能を用いてリージョンごと・時系列ごとでパーティションを分割するように設定してみました。
今回はPartition Projectionについてざっくりおさらいして、CloudTrailのPartition ProjectionのサンプルDDLをご紹介します。
これまで
CloudTrail画面から作成されるデフォルトのDDLを用いてAthenaでテーブルを作成して、 us-east-1
の結果を返すクエリを投げてみます。
デフォルトのDDL(クリックで展開)
CREATE EXTERNAL TABLE cloudtrail_logs ( eventVersion STRING, userIdentity STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, invokedBy: STRING, accessKeyId: STRING, userName: STRING, sessionContext: STRUCT< attributes: STRUCT< mfaAuthenticated: STRING, creationDate: STRING>, sessionIssuer: STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, userName: STRING>>>, eventTime STRING, eventSource STRING, eventName STRING, awsRegion STRING, sourceIpAddress STRING, userAgent STRING, errorCode STRING, errorMessage STRING, requestParameters STRING, responseElements STRING, additionalEventData STRING, requestId STRING, eventId STRING, resources ARRAY<STRUCT< arn: STRING, accountId: STRING, type: STRING>>, eventType STRING, apiVersion STRING, readOnly STRING, recipientAccountId STRING, serviceEventDetails STRING, sharedEventID STRING, vpcEndpointId STRING ) COMMENT 'CloudTrail table for [バケット名] bucket' ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://[バケット名]/AWSLogs/[アカウントID]/CloudTrail/' TBLPROPERTIES ('classification'='cloudtrail');
SELECT * FROM cloudtrail_logs WHERE awsregion = 'us-east-1' LIMIT 10;
これを流した結果がこちら。
実行時間は約1分、スキャンされたデータは778MBと、10件出力するだけで大量の余計なデータを含んで検索していることが分かります。
ここで、DDLを少々改善して、リージョン、年、月、日でパーティションを分割するよう設定してみましょう。
パーティションを切ったDDL(クリックで展開)
CREATE EXTERNAL TABLE cloudtrail_logs_partition ( eventVersion STRING, userIdentity STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, invokedBy: STRING, accessKeyId: STRING, userName: STRING, sessionContext: STRUCT< attributes: STRUCT< mfaAuthenticated: STRING, creationDate: STRING>, sessionIssuer: STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, userName: STRING>>>, eventTime STRING, eventSource STRING, eventName STRING, awsRegion STRING, sourceIpAddress STRING, userAgent STRING, errorCode STRING, errorMessage STRING, requestParameters STRING, responseElements STRING, additionalEventData STRING, requestId STRING, eventId STRING, resources ARRAY<STRUCT< arn: STRING, accountId: STRING, type: STRING>>, eventType STRING, apiVersion STRING, readOnly STRING, recipientAccountId STRING, serviceEventDetails STRING, sharedEventID STRING, vpcEndpointId STRING ) COMMENT 'CloudTrail table for [バケット名] bucket' PARTITIONED BY (region string, year string, month string, day string) ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://[バケット名]/AWSLogs/[アカウントID]/CloudTrail/' TBLPROPERTIES ('classification'='cloudtrail');
この場合、下記のように ALTER TABLE ADD PARTITION
を利用してパーティションをロードする事により、データをクエリできるようになります。
ALTER TABLE cloudtrail_logs ADD PARTITION (region='us-east-1',year='2021',month='01',day='05') LOCATION 's3://${BucketName}/AWSLogs/${AccountId}/CloudTrail/us-east-1/2021/01/05/';
ただ、これだと必要なパーティションを手動で都度ロードする必要があり、非常に面倒ですよね。
PARTITIONED BYで指定しているパーティションをリージョンだけにする事も可能ですが、それでも毎度 ALTER TABLE ADD PARTITION
を叩くのは面倒ですし、月・日単位でパーティションを切らないと無駄なコストも発生してしまいます。
Partition Projectionを使うとどうなるのか
Partition Projectionを使うと、 ALTER TABLE ADD PARTITION
でパーティションをロードする事無く、指定した内容で自動でパーティションを切ってくれます。
DDLにPartition Projectionの設定を仕込んで、後はSELECTを流すだけでOKです。
設定内容
今回作成したDDLは下記となります。
CREATE EXTERNAL TABLE cloudtrail_logs_partition_projection ( eventVersion STRING, userIdentity STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, invokedBy: STRING, accessKeyId: STRING, userName: STRING, sessionContext: STRUCT< attributes: STRUCT< mfaAuthenticated: STRING, creationDate: STRING>, sessionIssuer: STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, userName: STRING>>>, eventTime STRING, eventSource STRING, eventName STRING, awsRegion STRING, sourceIpAddress STRING, userAgent STRING, errorCode STRING, errorMessage STRING, requestParameters STRING, responseElements STRING, additionalEventData STRING, requestId STRING, eventId STRING, resources ARRAY<STRUCT< arn: STRING, accountId: STRING, type: STRING>>, eventType STRING, apiVersion STRING, readOnly STRING, recipientAccountId STRING, serviceEventDetails STRING, sharedEventID STRING, vpcEndpointId STRING ) COMMENT 'CloudTrail table for ${BucketName} bucket' PARTITIONED BY (region string, date string) ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://[バケット名]/AWSLogs/[アカウントID]/CloudTrail/' TBLPROPERTIES ( 'projection.enabled' = 'true', 'projection.date.type' = 'date', 'projection.date.range' = 'NOW-1YEARS,NOW', 'projection.date.format' = 'yyyy/MM/dd', 'projection.date.interval' = '1', 'projection.date.interval.unit' = 'DAYS', 'projection.region.type' = 'enum', 'projection.region.values'='us-east-1,us-east-2,us-west-1,us-west-2,af-south-1,ap-east-1,ap-south-1,ap-northeast-2,ap-southeast-1,ap-southeast-2,ap-northeast-1,ca-central-1,eu-central-1,eu-west-1,eu-west-2,eu-south-1,eu-west-3,eu-north-1,me-south-1,sa-east-1', 'storage.location.template' = 's3://[バケット名]/AWSLogs/[アカウントID]/CloudTrail/${region}/${date}', 'classification'='cloudtrail', 'compressionType'='gzip', 'typeOfData'='file', 'classification'='cloudtrail' );
ポイントはハイライトしている部分で、 PARTITION BY
でregionとdateを指定して、下部でPartition Projectionの設定をしてあげます。
Projection は date
と region(enum)
で行っており、 regionのenumは2021/02/08時点で利用可能なリージョン一覧を列挙しています。
こちらのテーブルでSELECTした結果、最適化できて、実行時間・スキャンデータが少なくなっていることを確認できます。
SELECT * FROM cloudtrail_logs_partition_projection WHERE region = 'us-east-1' LIMIT 10;
1日単位でパーティションを切るように指定しているため、リージョン&日付指定でのSELECTもサクサクです。
SELECT * FROM cloudtrail_logs_partition_projection WHERE region = 'us-east-1' AND date = '2021/01/01' LIMIT 10;
まとめ
AthenaのPartition Projectionを使うことで、CloudTrailのログでもリージョン別・日付別で ALTER TABLE ADD PARTITION
を叩くこと無くパーティションを設定することができます。
公式ドキュメントではリージョンに対応したPartition Projectionの例が記載されていなかったため記事にしてみました。
誰かのお役に立てれば幸いです。
参考
https://dev.classmethod.jp/articles/20200627-amazon-athena-partition-projection/
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/cloudtrail-logs.html